package com.jqh.myplayer.player;

import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.text.TextUtils;

import com.jqh.myplayer.MuteEnum;
import com.jqh.myplayer.TimeInfo;
import com.jqh.myplayer.listener.OnCompleteListener;
import com.jqh.myplayer.listener.OnErrorListener;
import com.jqh.myplayer.listener.OnLoadListener;
import com.jqh.myplayer.listener.OnParparedListener;
import com.jqh.myplayer.listener.OnPauseResumeListener;
import com.jqh.myplayer.listener.OnRecordTimeListener;
import com.jqh.myplayer.listener.OnTimeInfoListener;
import com.jqh.myplayer.listener.OnValumeDBListener;
import com.jqh.myplayer.log.JqhLog;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.sql.Time;

public class JqhPlayer {

    static {
        System.loadLibrary("jqhmusic");
        System.loadLibrary("avcodec-57");
        System.loadLibrary("avdevice-57");
        System.loadLibrary("avfilter-6");
        System.loadLibrary("avformat-57");
        System.loadLibrary("avutil-55");
        System.loadLibrary("postproc-54");
        System.loadLibrary("swresample-2");
        System.loadLibrary("swscale-4");
    }

    private static String source ;
    private static boolean playNext = false;
    private static int duration = -1;
    private OnParparedListener onParparedListener;
    private OnLoadListener onLoadListener;
    private OnPauseResumeListener onPauseResumeListener;
    private OnTimeInfoListener onTimeInfoListener;
    private OnErrorListener onErrorListener ;
    private OnCompleteListener onCompleteListener;
    private OnValumeDBListener onValumeDBListener;
    private OnRecordTimeListener onRecordTimeListener;
    private static TimeInfo timeInfo;
    private static int volumePercent = 100;
    private static MuteEnum muteEnum = MuteEnum.MUTE_CENTER;
    private static float speed = 1.0f , pitch = 1.0f;
    private double recordTime = 0;
    private int sampleRate = 0 ;

    public void setOnLoadListener(OnLoadListener onLoadListener) {
        this.onLoadListener = onLoadListener;
    }

    public void setOnParparedListener(OnParparedListener onParparedListener) {
        this.onParparedListener = onParparedListener;
    }

    public void setOnPauseResumeListener(OnPauseResumeListener onPauseResumeListener) {
        this.onPauseResumeListener = onPauseResumeListener;
    }

    public void setOnTimeInfoListener(OnTimeInfoListener onTimeInfoListener) {
        this.onTimeInfoListener = onTimeInfoListener;
    }

    public void setOnErrorListener(OnErrorListener onErrorListener) {
        this.onErrorListener = onErrorListener;
    }

    public void setOnCompleteListener(OnCompleteListener onCompleteListener) {
        this.onCompleteListener = onCompleteListener;
    }

    public void setOnValumeDBListener(OnValumeDBListener onValumeDBListener) {
        this.onValumeDBListener = onValumeDBListener;
    }

    public void setOnRecordTimeListener(OnRecordTimeListener onRecordTimeListener) {
        this.onRecordTimeListener = onRecordTimeListener;
    }

    public JqhPlayer(){

    }

    public void setSource(String source) {
        this.source = source;
    }

    public void parpared(){

        if (TextUtils.isEmpty(source)) {
            JqhLog.d("source not be empty");
            return;
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                n_parpared(source);
            }
        }).start();
    }

    public void start(){
        if (TextUtils.isEmpty(source)) {
            JqhLog.d("source not be empty");
            return;
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                setVolume(volumePercent);
                setMute(muteEnum);
                n_start();
            }
        }).start();

    }

    public void pause(){
        n_pause();
        if (onPauseResumeListener != null) onPauseResumeListener.onPause(true);
    }

    public void resume(){
        n_resume();
        if (onPauseResumeListener != null) onPauseResumeListener.onPause(false);

    }

    public void stop(){
        timeInfo = null;
        duration = -1;
        stopRecord();
        new Thread(new Runnable() {
            @Override
            public void run() {
                n_stop();
            }
        }).start();
    }

    public void seek(int seek) {
        n_seek(seek);
    }

    public void playNext(String url)
    {
        source = url;
        playNext = true;
        stop();
    }

    public int getDuration(){
        if (duration < 0) {
            duration = n_duration();
        }
        return duration;
    }

    public void setVolume(int percent) {
        if (percent >=0 && percent <= 100) {
            volumePercent = percent;
            n_volume(percent);
        }
    }

    public void setMute(MuteEnum mute){
        muteEnum = mute;
        n_setMute(mute.getValue());
    }

    public void startRecod(File outFile){
        sampleRate = n_samolerate();
        if (!initmediacodec) {
            if (sampleRate > 0) {
                initmediacodec = true;
                initMediaCodec(sampleRate, outFile);
                n_startstoprecord(true);
            }
        }

    }
    public void stopRecord(){
        if (initmediacodec) {
            n_startstoprecord(false);
            releaseMediacodec();
        }

    }

    public void pauseRecord(){
        n_startstoprecord(false);
    }

    public void resumeRecord(){
        n_startstoprecord(true);
    }
    public int getVolumePercent(){
        return volumePercent;
    }

    public void onCallNext()
    {
        if(playNext)
        {
            playNext = false;
            parpared();
        }
    }

    public void onCallParpared(){
        if (onParparedListener != null) {
            onParparedListener.onParpared();
        }
    }

    public void onCallLoad(boolean load) {
        if (onLoadListener != null) onLoadListener.onLoad(load);
    }

    public void onCallTimeInfo(int currentTime, int totalTime) {
        if (onTimeInfoListener != null){
            if (timeInfo == null) timeInfo = new TimeInfo();
            timeInfo.setCurrentTime(currentTime);
            timeInfo.setTotalTime(totalTime);
            onTimeInfoListener.onTimeInfo(timeInfo);
        }
    }

    public void onCallError(int code, String msg )  {
        stop();
        if (onErrorListener != null) onErrorListener.onError(code, msg);
    }

    public void onCallComplete(){
        stop();
        if (onCompleteListener != null) onCompleteListener.onComplete();
    }

    public  void onCallValumeDB(int db) {
        if (onValumeDBListener != null) onValumeDBListener.onDBValue(db);
    }

    public void setPitch(float _pitch){
        pitch = _pitch;
        n_pitch(pitch);
    }

    public void setSpeed(float _speed) {
        speed = _speed;
        n_speed(speed);
    }



    private native void n_parpared(String source);

    private native void n_start();

    public native void n_playpcm(String url);

    private native void n_pause();

    private native void n_resume();

    private native void n_stop();

    private native  void n_seek(int secds);
    private native int n_duration();
    private native void n_volume(int percent);
    private native void n_setMute(int mute);
    private native void n_speed(float speed);
    private native void n_pitch(float pitch);
    private native  int n_samolerate();
    private native void n_startstoprecord(boolean start);


    // bi边播放边录制
    private MediaFormat encoderFormat = null;

    private MediaCodec encoder = null;

    private FileOutputStream outputStream;

    private MediaCodec.BufferInfo info = null;
    private int perpcmsize = 0 ;
    private byte[] outByteBuffer = null;
    private int aacsamplerate = 4;

    private static boolean initmediacodec = false;

    private void initMediaCodec(int sampleRate, File outfile) {
        try {
            aacsamplerate = getADTSsamplerate(sampleRate);
            encoderFormat = MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_AAC, sampleRate, 2);
            encoderFormat.setInteger(MediaFormat.KEY_BIT_RATE, 96000);
            encoderFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
            encoderFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 4096);

            encoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AAC);
            if (encoder == null) {
                return;
            }

            info = new MediaCodec.BufferInfo();

            encoder.configure(encoderFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
            outputStream = new FileOutputStream(outfile);
            encoder.start();
        }catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void encodecPcmToAAC(int size, byte[] buffer) {
        if (buffer != null && encoder != null) {
            recordTime += size * 1.0 / (sampleRate * 2 * (16 / 8));
            JqhLog.d("recordTime = " + recordTime);
            if (onRecordTimeListener != null) onRecordTimeListener.onRecordTime((int)recordTime);
            int inputBufferIndex = encoder.dequeueInputBuffer(0);
            if (inputBufferIndex >= 0) {
                ByteBuffer byteBuffer = encoder.getInputBuffers()[inputBufferIndex];
                byteBuffer.clear();
                byteBuffer.put(buffer);
                encoder.queueInputBuffer(inputBufferIndex, 0 , size, 0 , 0);

            }

            int index = encoder.dequeueOutputBuffer(info, 0 );
            while(index >=0) {
                // 写文件
                try {
                    perpcmsize = info.size + 7;
                    outByteBuffer = new byte[perpcmsize];
                    ByteBuffer byteBuffer = encoder.getOutputBuffers()[index];
                    byteBuffer.position(info.offset);
                    byteBuffer.limit(info.offset + info.size);

                    // 添加头部信息
                    addADtsHeader(outByteBuffer, perpcmsize, aacsamplerate);

                    // 把bytebuffer放入outbuffer中，从第7个字节开始
                    byteBuffer.get(outByteBuffer, 7, info.size);
                    byteBuffer.position(info.offset);
                    outputStream.write(outByteBuffer, 0, perpcmsize);
                    encoder.releaseOutputBuffer(index, false);
                    // 在读一次，如果还有继续。如果没有就结束
                    index = encoder.dequeueOutputBuffer(info, 0 );
                    outByteBuffer = null;
                }catch ( IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    // 添加aac头
    private void addADtsHeader(byte[] packet, int packetLen, int samplerate) {
        int profile = 2; // AAC LC
        int freqIdx = samplerate; // samplerate
        int chanCfg = 2; // CPE
        packet[0] = (byte) 0xFF; // 0xFFF(12bit) 这里只取了8位，所以还差4位放到下一个里面
        packet[1] = (byte) 0xF9; // 第一个4bit位放F
        packet[2] = (byte) (((profile - 1) << 6) + (freqIdx << 2) + (chanCfg >> 2));
        packet[3] = (byte) (((chanCfg & 3) << 6) + (packetLen >> 11));
        packet[4] = (byte) ((packetLen & 0x7FF) >> 3);
        packet[5] = (byte) (((packetLen & 7) << 5) + 0x1F);
        packet[6] = (byte) 0xFC;
    }

    private int getADTSsamplerate(int samplerate)
    {
        int rate = 4;
        switch (samplerate)
        {
            case 96000:
                rate = 0;
                break;
            case 88200:
                rate = 1;
                break;
            case 64000:
                rate = 2;
                break;
            case 48000:
                rate = 3;
                break;
            case 44100:
                rate = 4;
                break;
            case 32000:
                rate = 5;
                break;
            case 24000:
                rate = 6;
                break;
            case 22050:
                rate = 7;
                break;
            case 16000:
                rate = 8;
                break;
            case 12000:
                rate = 9;
                break;
            case 11025:
                rate = 10;
                break;
            case 8000:
                rate = 11;
                break;
            case 7350:
                rate = 12;
                break;
        }
        return rate;
    }

    private void releaseMediacodec(){
        if (encoder == null) return ;
        try{
            recordTime = 0;
            outputStream.close();
            outputStream = null;

            encoder.stop();
            encoder.release();
            encoder = null;
            encoderFormat = null;
            info = null;
            initmediacodec = false;
            JqhLog.d("录制完成");
        }catch (IOException e) {
            e.printStackTrace();
        }
        finally {
            if (outputStream != null) {
                try{
                    outputStream.close();
                }catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
